import os
import jwt
import logging
from datetime import datetime, timedelta
from typing import Optional, Dict, Callable, List, Any
from fastapi import Request, HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import re
import httpx
import asyncio
from ..core.config import settings

# 配置日志
logger = logging.getLogger(__name__)

# 定义兼容前端的JWT密钥
JWT_FRONTEND_SECRET = "qqwwweerr"

class JWTService:
    """JWT服务类，用于处理JWT令牌的验证和解析"""
    
    def __init__(self, secret_key: str = None):
        """初始化JWT服务"""
        self.secret_key = secret_key or os.getenv("JWT_SECRET", "visitor_auth_secret_key_very_secure")  # 默认密钥
        # 额外保存前端使用的密钥，用于验证前端传来的token
        self.frontend_secret = JWT_FRONTEND_SECRET
        logger.debug(f"JWT Service initialized with default key: {'yes' if secret_key is None else 'no'}")
        self.algorithm = "HS256"
        self.security = HTTPBearer()
    
    def decode_token(self, token: str) -> Dict:
        """解码JWT令牌"""
        # 首先尝试用前端密钥验证
        try:
            payload = jwt.decode(
                token, 
                self.frontend_secret, 
                algorithms=[self.algorithm],
                options={"verify_exp": True}
            )
            return self._process_payload(payload)
        except jwt.ExpiredSignatureError:
            logger.warning("Token expired")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail={"message": "令牌已过期"}
            )
        except jwt.InvalidTokenError:
            # 前端密钥失败，尝试后端密钥
            try:
                payload = jwt.decode(
                    token, 
                    self.secret_key, 
                    algorithms=[self.algorithm],
                    options={"verify_exp": True}
                )
                return self._process_payload(payload)
            except jwt.ExpiredSignatureError:
                logger.warning("Token expired")
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail={"message": "令牌已过期"}
                )
            except jwt.InvalidTokenError as e:
                logger.warning(f"Invalid token: {str(e)}")
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail={"message": "无效的令牌"}
                )
        except Exception as e:
            logger.error(f"JWT验证出现意外错误: {str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, 
                detail={"message": "服务器内部错误"}
            )
    
    def verify_jwt(self, token: str) -> dict:
        """验证JWT令牌并返回解码后的payload"""
        # 首先尝试用前端密钥验证
        try:
            options = {"verify_exp": False}  # 不验证过期时间，避免无效请求
            payload = jwt.decode(token, JWT_FRONTEND_SECRET, algorithms=["HS256"], options=options)
            return self._process_payload(payload)
        except Exception as e:
            # 如果失败，尝试后端密钥
            try:
                payload = jwt.decode(token, self.secret_key, algorithms=["HS256"], options={"verify_exp": False})
                return self._process_payload(payload)
            except Exception:
                # 所有尝试都失败
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="Invalid token"
                )
    
    def _process_payload(self, payload):
        """处理JWT payload，确保兼容性"""
        # 兼容性处理：如果payload中包含uuid而不是sub，将uuid值赋给sub
        if "uuid" in payload and "sub" not in payload:
            payload["sub"] = payload["uuid"]
        
        # 如果缺少sub字段但有type为visitor，设置sub为visitor
        if "sub" not in payload and "type" in payload and payload["type"] == "visitor":
            payload["sub"] = "visitor"
        
        return payload
    
    def parse_expiration_time(self, expires_in: str) -> timedelta:
        """解析过期时间字符串，转为timedelta对象"""
        pattern = r'(\d+)([smhd])'
        match = re.match(pattern, expires_in)
        
        if not match:
            raise ValueError(f"Invalid expiration format: {expires_in}")
        
        value, unit = match.groups()
        value = int(value)
        
        if unit == 's':
            return timedelta(seconds=value)
        elif unit == 'm':
            return timedelta(minutes=value)
        elif unit == 'h':
            return timedelta(hours=value)
        elif unit == 'd':
            return timedelta(days=value)
        else:
            raise ValueError(f"Invalid time unit: {unit}")
            
    def extract_token_from_request(self, request: Request) -> str:
        """
        从请求头、查询参数或cookie中提取JWT令牌
        """
        # 从Authorization头中提取
        auth_header = request.headers.get("Authorization")
        if auth_header and auth_header.startswith("Bearer "):
            return auth_header.replace("Bearer ", "")
            
        # 从查询参数中提取
        token = request.query_params.get("token")
        if token:
            return token
            
        # 从cookie中提取
        token = request.cookies.get("token")
        if token:
            return token
            
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, 
            detail={"message": "未提供授权令牌"}
        )
    
    async def verify_request(self, request: Request) -> dict:
        """
        验证请求中的JWT令牌
        """
        token = self.extract_token_from_request(request)
        return self.decode_token(token)

# 创建JWT服务实例
jwt_service = JWTService()

async def jwt_required(request: Request):
    """验证请求中的JWT令牌"""
    # 检查Authorization头
    auth_header = request.headers.get("Authorization")
    if not auth_header:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Missing authorization header"
        )
    
    # 分割和验证令牌格式
    try:
        scheme, token = auth_header.split()
        if scheme.lower() != "bearer":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication scheme"
            )
    except ValueError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token format"
        )
    
    # 验证令牌
    try:
        payload = jwt_service.verify_jwt(token)
        
        # 将用户数据保存到请求状态
        request.state.user = payload
        return payload
    except HTTPException as e:
        raise e
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token"
        )

# 简化版依赖函数，用于路由保护
async def jwt_required_simple(request: Request) -> dict:
    """
    FastAPI依赖函数，用于保护需要JWT认证的路由
    """
    return await jwt_service.verify_request(request)

async def send_token_request(reserve_id: str, is_success: bool) -> None:
    """
    发送token确认或取消请求
    
    Args:
        reserve_id: 预留ID
        is_success: 是否成功，True发送确认请求，False发送取消请求
    """
    if not reserve_id:
        return
        
    try:
        url = settings.token_confirm_api if is_success else settings.token_cancel_api
        payload = {"reserve_id": reserve_id}
        
        async with httpx.AsyncClient(timeout=10.0) as client:
            response = await client.post(url, json=payload)
            
            if response.status_code == 200:
                logger.info(f"Token {'confirm' if is_success else 'cancel'} request sent successfully for reserve_id: {reserve_id}")
            else:
                logger.warning(f"Token {'confirm' if is_success else 'cancel'} request failed with status {response.status_code} for reserve_id: {reserve_id}")
                
    except Exception as e:
        logger.error(f"Failed to send token {'confirm' if is_success else 'cancel'} request for reserve_id {reserve_id}: {e}")


def send_token_request_background(reserve_id: str, is_success: bool) -> None:
    """
    在后台发送token请求（非阻塞）
    
    Args:
        reserve_id: 预留ID  
        is_success: 是否成功
    """
    if not reserve_id:
        return
        
    try:
        loop = asyncio.get_event_loop()
        loop.create_task(send_token_request(reserve_id, is_success))
    except RuntimeError:
        # 如果没有事件循环，创建新的
        asyncio.create_task(send_token_request(reserve_id, is_success))
    except Exception as e:
        logger.error(f"Failed to create background task for token request: {e}") 